// DbGet.cpp
#include "DbGet.h"
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <cstdlib> // For std::strtol, std::strtod, std::strtoll

// --- 辅助宏或函数 (可选，用于简化错误处理) ---
// 注意：宏现在只处理异常，返回值由函数逻辑决定
#define HANDLE_DB_EXCEPTION(try_block, error_msg_var) \
    try { \
        try_block \
    } catch (const std::exception& e) { \
        error_msg_var = "Database get operation failed: "; \
        error_msg_var += e.what(); \
        std::cerr << error_msg_var << std::endl; \
        return GetResult::Error; \
    } catch (...) { \
        error_msg_var = "Database get operation failed: Unknown error occurred."; \
        std::cerr << error_msg_var << std::endl; \
        return GetResult::Error; \
    }

// --- 私有辅助函数实现 ---

void DbGet::split_string_to_repeated(const std::string& str, const std::string& delimiter, ::google::protobuf::RepeatedPtrField<std::string>* repeated_field) {
    if (str.empty()) {
        return;
    }
    size_t start = 0;
    size_t end = str.find(delimiter);
    while (end != std::string::npos) {
        repeated_field->Add()->assign(str.substr(start, end - start));
        start = end + delimiter.length();
        end = str.find(delimiter, start);
    }
    // Add the last segment
    repeated_field->Add()->assign(str.substr(start));
}

// 辅助函数：从 neo4j_value_t 获取字符串
std::string get_string_from_neo4j_value(neo4j_value_t value) {
    if (neo4j_type(value) == NEO4J_STRING) {
        // 对于非字符串类型，转换为字符串
        char buffer[4096];
        neo4j_tostring(value, buffer, sizeof(buffer));
        return std::string(buffer);
    } 
    return "";
}

// 辅助函数：从 neo4j_value_t 获取整数
int64_t get_int_from_neo4j_value(neo4j_value_t value) {
    if (neo4j_type(value) == NEO4J_INT) {
        return neo4j_int_value(value);
    }
    return 0;
}

// 辅助函数：从 neo4j_value_t 获取布尔值
bool get_bool_from_neo4j_value(neo4j_value_t value) {
    if (neo4j_type(value) == NEO4J_BOOL) {
        return neo4j_bool_value(value);
    }
    return false;
}

// 辅助函数：从 neo4j_value_t 获取浮点数
double get_float_from_neo4j_value(neo4j_value_t value) {
    if (neo4j_type(value) == NEO4J_FLOAT) {
        return neo4j_float_value(value);
    }
    return 0.0;
}

// --- Get 方法实现 (返回 GetResult) ---

GetResult DbGet::GetUser(int32_t user_id, ::graph::UserNode& user_node, std::string& error_message) {
    const std::string cypher_query =
        "MATCH (u:User {id: $target_id}) "
        "RETURN u.id, u.username, u.email, u.password_hash, u.created_at, u.updated_at, "
        "       u.age_group, u.gender, u.location, u.activity_level, u.interests_str";

    // 构建参数
    neo4j_map_entry_t entries[] = {
        { .key = neo4j_string("target_id"), .value = neo4j_int(user_id) }
    };
    neo4j_value_t params = neo4j_map(entries, 1);

    HANDLE_DB_EXCEPTION(
        {
            DbClient& db_client = DbClient::getInstance();
            neo4j_result_stream_t* result_stream = db_client.run(cypher_query.c_str(), params);

            if (result_stream == nullptr) {
                error_message = "GetUser: Failed to execute query.";
                return GetResult::Error;
            }

            neo4j_result_t* result = neo4j_fetch_next(result_stream);
            if (result == nullptr) {
                neo4j_close_results(result_stream);
                std::cout << "GetUser: User with ID " << user_id << " not found." << std::endl;
                return GetResult::NotFound; // 明确返回 NotFound
            }

            // 检查是否有多个结果
            neo4j_result_t* next_result = neo4j_fetch_next(result_stream);
            if (next_result != nullptr) {
                std::cerr << "GetUser: Warning: Found multiple users with ID " << user_id << ". Returning the first one." << std::endl;
                neo4j_close_results(result_stream);
                // 重新执行查询获取第一个结果
                neo4j_result_stream_t* new_result_stream = db_client.run(cypher_query.c_str(), params);
                neo4j_fetch_next(new_result_stream);
                neo4j_close_results(result_stream);
                result_stream = new_result_stream;
            }

            // 提取数据
            try {
                neo4j_value_t id_val = neo4j_result_field(result, 0);
                neo4j_value_t username_val = neo4j_result_field(result, 1);
                neo4j_value_t email_val = neo4j_result_field(result, 2);
                neo4j_value_t password_hash_val = neo4j_result_field(result, 3);
                neo4j_value_t created_at_val = neo4j_result_field(result, 4);
                neo4j_value_t updated_at_val = neo4j_result_field(result, 5);
                neo4j_value_t age_group_val = neo4j_result_field(result, 6);
                neo4j_value_t gender_val = neo4j_result_field(result, 7);
                neo4j_value_t location_val = neo4j_result_field(result, 8);
                neo4j_value_t activity_level_val = neo4j_result_field(result, 9);
                neo4j_value_t interests_str_val = neo4j_result_field(result, 10);

                user_node.set_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(id_val)));
                user_node.set_username(get_string_from_neo4j_value(username_val));
                user_node.set_email(get_string_from_neo4j_value(email_val));
                user_node.set_password_hash(get_string_from_neo4j_value(password_hash_val));
                user_node.set_created_at(get_string_from_neo4j_value(created_at_val));
                user_node.set_updated_at(get_string_from_neo4j_value(updated_at_val));
                user_node.set_age_group(get_string_from_neo4j_value(age_group_val));
                user_node.set_gender(get_string_from_neo4j_value(gender_val));
                user_node.set_location(get_string_from_neo4j_value(location_val));
                user_node.set_activity_level(get_string_from_neo4j_value(activity_level_val));
                
                std::string interests_str = get_string_from_neo4j_value(interests_str_val);
                split_string_to_repeated(interests_str, ";", user_node.mutable_interests());

                neo4j_close_results(result_stream);
            } catch (const std::exception& e) {
                neo4j_close_results(result_stream);
                error_message = "GetUser: Error parsing data from query result: ";
                error_message += e.what();
                return GetResult::Error; // 解析错误
            }

            std::cout << "Successfully retrieved User node with ID: " << user_id << std::endl;
            return GetResult::Found; // 明确返回 Found
        },
        error_message // error_message 会在 HANDLE_DB_EXCEPTION 内部被设置
        // HANDLE_DB_EXCEPTION 会处理所有异常并返回 GetResult::Error
    )
    // 如果没有异常且 HANDLE_DB_EXCEPTION 没有返回，说明流程有问题（理论上 unreachable）
    // 但为了编译器满意，可以加一个 fallback return
    error_message = "GetUser: Unexpected code path reached."; 
    return GetResult::Error;
}

GetResult DbGet::GetList(int32_t list_id, ::graph::ListNode& list_node, std::string& error_message) {
    const std::string cypher_query =
        "MATCH (l:List {id: $target_id}) "
        "RETURN l.id, l.user_id, l.title, l.is_urgent, l.is_collaborative, l.priority, "
        "       l.location_scope, l.publish_date, l.start_time, l.end_time, l.is_public, "
        "       l.view_count, l.like_count, l.comment_count, l.created_at, l.updated_at, "
        "       l.category, l.tags_str";

    // 构建参数
    neo4j_map_entry_t entries[] = {
        { .key = neo4j_string("target_id"), .value = neo4j_int(list_id) }
    };
    neo4j_value_t params = neo4j_map(entries, 1);

    HANDLE_DB_EXCEPTION(
        {
            DbClient& db_client = DbClient::getInstance();
            neo4j_result_stream_t* result_stream = db_client.run(cypher_query.c_str(), params);

            if (result_stream == nullptr) {
                error_message = "GetList: Failed to execute query.";
                return GetResult::Error;
            }

            neo4j_result_t* result = neo4j_fetch_next(result_stream);
            if (result == nullptr) {
                neo4j_close_results(result_stream);
                std::cout << "GetList: List with ID " << list_id << " not found." << std::endl;
                return GetResult::NotFound;
            }

            // 检查是否有多个结果
            neo4j_result_t* next_result = neo4j_fetch_next(result_stream);
            if (next_result != nullptr) {
                std::cerr << "GetList: Warning: Found multiple lists with ID " << list_id << ". Returning the first one." << std::endl;
                neo4j_close_results(result_stream);
                // 重新执行查询获取第一个结果
                neo4j_result_stream_t* new_result_stream = db_client.run(cypher_query.c_str(), params);
                neo4j_fetch_next(new_result_stream);
                neo4j_close_results(result_stream);
                result_stream = new_result_stream;
            }

            try {
                neo4j_value_t id_val = neo4j_result_field(result, 0);
                neo4j_value_t user_id_val = neo4j_result_field(result, 1);
                neo4j_value_t title_val = neo4j_result_field(result, 2);
                neo4j_value_t is_urgent_val = neo4j_result_field(result, 3);
                neo4j_value_t is_collaborative_val = neo4j_result_field(result, 4);
                neo4j_value_t priority_val = neo4j_result_field(result, 5);
                neo4j_value_t location_scope_val = neo4j_result_field(result, 6);
                neo4j_value_t publish_date_val = neo4j_result_field(result, 7);
                neo4j_value_t start_time_val = neo4j_result_field(result, 8);
                neo4j_value_t end_time_val = neo4j_result_field(result, 9);
                neo4j_value_t is_public_val = neo4j_result_field(result, 10);
                neo4j_value_t view_count_val = neo4j_result_field(result, 11);
                neo4j_value_t like_count_val = neo4j_result_field(result, 12);
                neo4j_value_t comment_count_val = neo4j_result_field(result, 13);
                neo4j_value_t created_at_val = neo4j_result_field(result, 14);
                neo4j_value_t updated_at_val = neo4j_result_field(result, 15);
                neo4j_value_t category_val = neo4j_result_field(result, 16);
                neo4j_value_t tags_str_val = neo4j_result_field(result, 17);

                list_node.set_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(id_val)));
                list_node.set_user_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(user_id_val)));
                list_node.set_title(get_string_from_neo4j_value(title_val));
                list_node.set_is_urgent(get_bool_from_neo4j_value(is_urgent_val));
                list_node.set_is_collaborative(get_bool_from_neo4j_value(is_collaborative_val));
                list_node.set_priority(get_string_from_neo4j_value(priority_val));
                list_node.set_location_scope(get_string_from_neo4j_value(location_scope_val));
                list_node.set_publish_date(get_string_from_neo4j_value(publish_date_val));
                list_node.set_start_time(get_string_from_neo4j_value(start_time_val));
                list_node.set_end_time(get_string_from_neo4j_value(end_time_val));
                list_node.set_is_public(get_bool_from_neo4j_value(is_public_val));
                list_node.set_view_count(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(view_count_val)));
                list_node.set_like_count(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(like_count_val)));
                list_node.set_comment_count(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(comment_count_val)));
                list_node.set_created_at(get_string_from_neo4j_value(created_at_val));
                list_node.set_updated_at(get_string_from_neo4j_value(updated_at_val));
                list_node.set_category(get_string_from_neo4j_value(category_val));
                
                std::string tags_str = get_string_from_neo4j_value(tags_str_val);
                split_string_to_repeated(tags_str, ";", list_node.mutable_tags());

                neo4j_close_results(result_stream);
            } catch (const std::exception& e) {
                neo4j_close_results(result_stream);
                error_message = "GetList: Error parsing data from query result: ";
                error_message += e.what();
                return GetResult::Error;
            }

            std::cout << "Successfully retrieved List node with ID: " << list_id << std::endl;
            return GetResult::Found;
        },
        error_message
    )
    error_message = "GetList: Unexpected code path reached."; 
    return GetResult::Error;
}

// --- 为其他 Get* 方法实现类似的逻辑 ---
GetResult DbGet::GetTodo(int32_t todo_id, ::graph::TodoNode& todo_node, std::string& error_message) {
    const std::string cypher_query =
        "MATCH (t:Todo {id: $target_id}) "
        "RETURN t.id, t.list_id, t.content, t.is_completed, t.sort_order, t.created_at, t.category, t.tags_str";

    // 构建参数
    neo4j_map_entry_t entries[] = {
        { .key = neo4j_string("target_id"), .value = neo4j_int(todo_id) }
    };
    neo4j_value_t params = neo4j_map(entries, 1);

    HANDLE_DB_EXCEPTION(
        {
            DbClient& db_client = DbClient::getInstance();
            neo4j_result_stream_t* result_stream = db_client.run(cypher_query.c_str(), params);

            if (result_stream == nullptr) {
                error_message = "GetTodo: Failed to execute query.";
                return GetResult::Error;
            }

            neo4j_result_t* result = neo4j_fetch_next(result_stream);
            if (result == nullptr) {
                neo4j_close_results(result_stream);
                std::cout << "GetTodo: Todo with ID " << todo_id << " not found." << std::endl;
                return GetResult::NotFound;
            }

            // 检查是否有多个结果
            neo4j_result_t* next_result = neo4j_fetch_next(result_stream);
            if (next_result != nullptr) {
                std::cerr << "GetTodo: Warning: Found multiple todos with ID " << todo_id << ". Returning the first one." << std::endl;
                neo4j_close_results(result_stream);
                // 重新执行查询获取第一个结果
                neo4j_result_stream_t* new_result_stream = db_client.run(cypher_query.c_str(), params);
                neo4j_fetch_next(new_result_stream);
                neo4j_close_results(result_stream);
                result_stream = new_result_stream;
            }

            try {
                neo4j_value_t id_val = neo4j_result_field(result, 0);
                neo4j_value_t list_id_val = neo4j_result_field(result, 1);
                neo4j_value_t content_val = neo4j_result_field(result, 2);
                neo4j_value_t is_completed_val = neo4j_result_field(result, 3);
                neo4j_value_t sort_order_val = neo4j_result_field(result, 4);
                neo4j_value_t created_at_val = neo4j_result_field(result, 5);
                neo4j_value_t category_val = neo4j_result_field(result, 6);
                neo4j_value_t tags_str_val = neo4j_result_field(result, 7);

                todo_node.set_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(id_val)));
                todo_node.set_list_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(list_id_val)));
                todo_node.set_content(get_string_from_neo4j_value(content_val));
                todo_node.set_is_completed(get_bool_from_neo4j_value(is_completed_val));
                todo_node.set_sort_order(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(sort_order_val)));
                todo_node.set_created_at(get_string_from_neo4j_value(created_at_val));
                todo_node.set_category(get_string_from_neo4j_value(category_val));
                
                std::string tags_str = get_string_from_neo4j_value(tags_str_val);
                split_string_to_repeated(tags_str, ";", todo_node.mutable_tags());

                neo4j_close_results(result_stream);
            } catch (const std::exception& e) {
                neo4j_close_results(result_stream);
                error_message = "GetTodo: Error parsing data from query result: ";
                error_message += e.what();
                return GetResult::Error;
            }

            std::cout << "Successfully retrieved Todo node with ID: " << todo_id << std::endl;
            return GetResult::Found;
        },
        error_message
    )
    error_message = "GetTodo: Unexpected code path reached."; 
    return GetResult::Error;
}

GetResult DbGet::GetComment(int32_t comment_id, ::graph::CommentNode& comment_node, std::string& error_message) {
    const std::string cypher_query =
        "MATCH (c:Comment {id: $target_id}) "
        "RETURN c.id, c.list_id, c.user_id, c.content, c.created_at";

    // 构建参数
    neo4j_map_entry_t entries[] = {
        { .key = neo4j_string("target_id"), .value = neo4j_int(comment_id) }
    };
    neo4j_value_t params = neo4j_map(entries, 1);

    HANDLE_DB_EXCEPTION(
        {
            DbClient& db_client = DbClient::getInstance();
            neo4j_result_stream_t* result_stream = db_client.run(cypher_query.c_str(), params);

            if (result_stream == nullptr) {
                error_message = "GetComment: Failed to execute query.";
                return GetResult::Error;
            }

            neo4j_result_t* result = neo4j_fetch_next(result_stream);
            if (result == nullptr) {
                neo4j_close_results(result_stream);
                std::cout << "GetComment: Comment with ID " << comment_id << " not found." << std::endl;
                return GetResult::NotFound;
            }

            // 检查是否有多个结果
            neo4j_result_t* next_result = neo4j_fetch_next(result_stream);
            if (next_result != nullptr) {
                std::cerr << "GetComment: Warning: Found multiple comments with ID " << comment_id << ". Returning the first one." << std::endl;
                neo4j_close_results(result_stream);
                // 重新执行查询获取第一个结果
                neo4j_result_stream_t* new_result_stream = db_client.run(cypher_query.c_str(), params);
                neo4j_fetch_next(new_result_stream);
                neo4j_close_results(result_stream);
                result_stream = new_result_stream;
            }

            try {
                neo4j_value_t id_val = neo4j_result_field(result, 0);
                neo4j_value_t list_id_val = neo4j_result_field(result, 1);
                neo4j_value_t user_id_val = neo4j_result_field(result, 2);
                neo4j_value_t content_val = neo4j_result_field(result, 3);
                neo4j_value_t created_at_val = neo4j_result_field(result, 4);

                comment_node.set_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(id_val)));
                comment_node.set_list_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(list_id_val)));
                comment_node.set_user_id(static_cast<::google::protobuf::int32>(get_int_from_neo4j_value(user_id_val)));
                comment_node.set_content(get_string_from_neo4j_value(content_val));
                comment_node.set_created_at(get_string_from_neo4j_value(created_at_val));

                neo4j_close_results(result_stream);
            } catch (const std::exception& e) {
                neo4j_close_results(result_stream);
                error_message = "GetComment: Error parsing data from query result: ";
                error_message += e.what();
                return GetResult::Error;
            }

            std::cout << "Successfully retrieved Comment node with ID: " << comment_id << std::endl;
            return GetResult::Found;
        },
        error_message
    )
    error_message = "GetComment: Unexpected code path reached."; 
    return GetResult::Error;
}

GetResult DbGet::GetEntity(const std::string& entity_id, ::graph::EntityNode& entity_node, std::string& error_message) {
    const std::string cypher_query =
        "MATCH (e:Entity {id: $target_id}) "
        "RETURN e.id, e.name, e.type, e.category, e.popularity_score, e.created_at";

    // 构建参数
    neo4j_map_entry_t entries[] = {
        { .key = neo4j_string("target_id"), .value = neo4j_string(entity_id.c_str()) }
    };
    neo4j_value_t params = neo4j_map(entries, 1);

    HANDLE_DB_EXCEPTION(
        {
            DbClient& db_client = DbClient::getInstance();
            neo4j_result_stream_t* result_stream = db_client.run(cypher_query.c_str(), params);

            if (result_stream == nullptr) {
                error_message = "GetEntity: Failed to execute query.";
                return GetResult::Error;
            }

            neo4j_result_t* result = neo4j_fetch_next(result_stream);
            if (result == nullptr) {
                neo4j_close_results(result_stream);
                std::cout << "GetEntity: Entity with ID '" << entity_id << "' not found." << std::endl;
                return GetResult::NotFound;
            }

            // 检查是否有多个结果
            neo4j_result_t* next_result = neo4j_fetch_next(result_stream);
            if (next_result != nullptr) {
                std::cerr << "GetEntity: Warning: Found multiple entities with ID '" << entity_id << "'. Returning the first one." << std::endl;
                neo4j_close_results(result_stream);
                // 重新执行查询获取第一个结果
                neo4j_result_stream_t* new_result_stream = db_client.run(cypher_query.c_str(), params);
                neo4j_fetch_next(new_result_stream);
                neo4j_close_results(result_stream);
                result_stream = new_result_stream;
            }

            try {
                neo4j_value_t id_val = neo4j_result_field(result, 0);
                neo4j_value_t name_val = neo4j_result_field(result, 1);
                neo4j_value_t type_val = neo4j_result_field(result, 2);
                neo4j_value_t category_val = neo4j_result_field(result, 3);
                neo4j_value_t popularity_score_val = neo4j_result_field(result, 4);
                neo4j_value_t created_at_val = neo4j_result_field(result, 5);

                entity_node.set_id(get_string_from_neo4j_value(id_val)); // string ID
                entity_node.set_name(get_string_from_neo4j_value(name_val));
                entity_node.set_type(get_string_from_neo4j_value(type_val));
                entity_node.set_category(get_string_from_neo4j_value(category_val));
                entity_node.set_popularity_score(get_float_from_neo4j_value(popularity_score_val));
                entity_node.set_created_at(get_string_from_neo4j_value(created_at_val));

                neo4j_close_results(result_stream);
            } catch (const std::exception& e) {
                neo4j_close_results(result_stream);
                error_message = "GetEntity: Error parsing data from query result: ";
                error_message += e.what();
                return GetResult::Error;
            }

            std::cout << "Successfully retrieved Entity node with ID: " << entity_id << std::endl;
            return GetResult::Found;
        },
        error_message
    )
    error_message = "GetEntity: Unexpected code path reached."; 
    return GetResult::Error;
}